package cn.yangliu.jpa.handler;

import java.util.List;

import javax.persistence.EntityManagerFactory;
import javax.persistence.TypedQuery;
import javax.sql.DataSource;

import cn.yangliu.jpa.enums.DbTypeEnum;
import cn.yangliu.jpa.function.ParamTransformer;
import cn.yangliu.jpa.function.PredicateBuilder;
import cn.yangliu.jpa.function.ValueTransformer;
import cn.yangliu.jpa.tools.JpaUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;


/**
 * @author 杨柳
 * @date 2019-06-12
 */
public class JpaHandler {

    public static final JpaHandler INSTANCE = new JpaHandler();

    private JpaHandler() {
    }

    public static void setDefaultDbType(DbTypeEnum defaultDbType) {
        JpaUtils.defaultDbType = defaultDbType;
    }

    public static void setThreadDbType(DbTypeEnum dbType) {
        JpaUtils.THREAD_LOCAL.set(dbType);
    }

    /**
     * 构建Specification 查询条件
     *
     * @param queryPojo 查询封装
     * @param <T>       实体类型
     * @return Specification
     */
    public <T> Specification<T> buildSpecification(Object queryPojo) {
        return SpecificationHandler.buildSpecification(queryPojo);
    }

    /**
     * 构建Specification 查询条件
     *
     * @param queryPojo 查询封装
     * @param builder   builder
     * @param <T>       实体类型
     * @return Specification
     */
    public <T> Specification<T> buildSpecification(Object queryPojo, PredicateBuilder builder) {
        return SpecificationHandler.buildSpecification(queryPojo, builder);
    }

    /**
     * 通过动态sql 实现复杂查询并分页
     *
     * @param dataSource 数据源
     * @param sourceSql  源sql
     * @param queryPojo  查询条件封装
     * @param pageable   分页条件
     * @param clazz      返回结果类型
     * @param <T>        泛型
     * @return list数据
     */
    public <T> Page<T> queryForListBySql(DataSource dataSource, String sourceSql, Object queryPojo,
                                         Pageable pageable, Class<T> clazz) {
        return SqlHandler.queryForListBySql(dataSource, sourceSql, queryPojo, pageable, clazz, null, null);
    }

    /**
     * 通过动态sql 实现复杂查询并分页
     *
     * @param dataSource       数据源
     * @param sourceSql        源sql
     * @param queryPojo        查询条件封装
     * @param pageable         分页条件
     * @param clazz            返回结果类型
     * @param paramTransformer 参数转换器
     * @param valueTransformer 值转换器
     * @param <T>              泛型
     * @return list数据
     */
    public <T> Page<T> queryForListBySql(DataSource dataSource, String sourceSql, Object queryPojo,
                                         Pageable pageable, Class<T> clazz, ParamTransformer paramTransformer,
                                         ValueTransformer valueTransformer) {
        return SqlHandler.queryForListBySql(dataSource, sourceSql, queryPojo, pageable, clazz, paramTransformer,
                valueTransformer);
    }

    /**
     * 通过动态sql 实现复杂查询并映射
     *
     * @param dataSource 数据源
     * @param sourceSql  源sql
     * @param queryPojo  查询条件封装
     * @param clazz      返回结果类型
     * @param <T>        泛型
     * @return 单条数据
     */
    public <T> T queryForObjectBySql(DataSource dataSource, String sourceSql, Object queryPojo, Class<T> clazz) {
        return SqlHandler.queryForObjectBySql(dataSource, sourceSql, queryPojo, clazz, null, null);
    }

    /**
     * 通过动态sql 实现复杂查询并映射
     *
     * @param dataSource       数据源
     * @param sourceSql        源sql
     * @param queryPojo        查询条件封装
     * @param clazz            返回结果类型
     * @param paramTransformer 参数转换器
     * @param valueTransformer 结果转换器
     * @param <T>              泛型
     * @return 单条数据
     */
    public <T> T queryForObjectBySql(DataSource dataSource, String sourceSql, Object queryPojo, Class<T> clazz,
                                     ParamTransformer paramTransformer, ValueTransformer valueTransformer) {
        return SqlHandler.queryForObjectBySql(dataSource, sourceSql, queryPojo, clazz, paramTransformer,
                valueTransformer);
    }

    /**
     * 构建jpal查询对象
     *
     * @param entityManagerFactory entityManagerFactory
     * @param queryPojo            查询实体对象封装
     * @param <T>                  实体类型
     * @return 查询对象
     */
    public <T> TypedQuery<T> buildJpqlQuery(EntityManagerFactory entityManagerFactory, Object queryPojo,
                                            Class<T> clazz) {
        return JpqlHandler.buildJpqlQuery(entityManagerFactory, queryPojo, clazz);
    }

    /**
     * 构建jpal查询对象
     *
     * @param entityManagerFactory entityManagerFactory
     * @param queryPojo            查询实体对象封装
     * @param orderBy              排序
     * @param <T>                  实体类型
     * @return 查询对象
     */
    public <T> TypedQuery<T> buildJpqlQuery(EntityManagerFactory entityManagerFactory, Object queryPojo,
                                            Class<T> clazz, String orderBy) {
        return JpqlHandler.buildJpqlQuery(entityManagerFactory, queryPojo, clazz, orderBy);
    }


    /**
     * 构建jpql语句
     *
     * @param sourceJpql   没写where的jpql
     * @param queryPojo    参数封装对象
     * @param params       外部传入的一个空list 用于临时存储参数
     * @param fields       外部传入的一个空list 用于临时存储属性名
     * @param orderAndPage 排序和分页
     * @return 完整的jpql
     */
    public String buildJpql(String sourceJpql, Object queryPojo, List<Object> params, List<String> fields,
                            String orderAndPage) {
        return JpqlHandler.buildJpql(sourceJpql, queryPojo, params, fields, orderAndPage);
    }

    /**
     * 构建jpql语句
     *
     * @param sourceJpql 没写where的jpql
     * @param queryPojo  参数封装对象
     * @param params     外部传入的一个空list 用于临时存储参数
     * @param fields     外部传入的一个空list 用于临时存储属性名
     * @return 完整的jpql
     */
    public String buildJpql(String sourceJpql, Object queryPojo, List<Object> params, List<String> fields) {
        return JpqlHandler.buildJpql(sourceJpql, queryPojo, params, fields, null);
    }


    /**
     * 构建TypedQuery
     *
     * @param entityManagerFactory entityManagerFactory
     * @param jpql                 jpql
     * @param clazz                目标对象类
     * @param params               参数list
     * @param fields               属性名
     * @param <T>                  泛型
     * @return TypedQuery
     */
    public <T> TypedQuery<T> buildQueryParameters(EntityManagerFactory entityManagerFactory, String jpql,
                                                  Class<T> clazz, List<Object> params, List<String> fields) {
        return JpqlHandler.buildQueryParameters(entityManagerFactory, jpql, clazz, params, fields);
    }
}